{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# python notebook for Make Your Own Neural Network\n",
    "# code for a 3-layer neural network, and code for learning the MNIST dataset\n",
    "# this version asks the network what the image should be, given a label\n",
    "# (c) Tariq Rashid, 2016\n",
    "# license is GPLv2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy\n",
    "# scipy.special for the sigmoid function expit(), and its inverse logit()\n",
    "import scipy.special\n",
    "# library for plotting arrays\n",
    "import matplotlib.pyplot\n",
    "# ensure the plots are inside this notebook, not an external window\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# neural network class definition\n",
    "class neuralNetwork:\n",
    "    \n",
    "    \n",
    "    # initialise the neural network\n",
    "    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):\n",
    "        # set number of nodes in each input, hidden, output layer\n",
    "        self.inodes = inputnodes\n",
    "        self.hnodes = hiddennodes\n",
    "        self.onodes = outputnodes\n",
    "        \n",
    "        # link weight matrices, wih and who\n",
    "        # weights inside the arrays are w_i_j, where link is from node i to node j in the next layer\n",
    "        # w11 w21\n",
    "        # w12 w22 etc \n",
    "        self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))\n",
    "        self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))\n",
    "\n",
    "        # learning rate\n",
    "        self.lr = learningrate\n",
    "        \n",
    "        # activation function is the sigmoid function\n",
    "        self.activation_function = lambda x: scipy.special.expit(x)\n",
    "        self.inverse_activation_function = lambda x: scipy.special.logit(x)\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # train the neural network\n",
    "    def train(self, inputs_list, targets_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        targets = numpy.array(targets_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        # output layer error is the (target - actual)\n",
    "        output_errors = targets - final_outputs\n",
    "        # hidden layer error is the output_errors, split by weights, recombined at hidden nodes\n",
    "        hidden_errors = numpy.dot(self.who.T, output_errors) \n",
    "        \n",
    "        # update the weights for the links between the hidden and output layers\n",
    "        self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))\n",
    "        \n",
    "        # update the weights for the links between the input and hidden layers\n",
    "        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # query the neural network\n",
    "    def query(self, inputs_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        return final_outputs\n",
    "    \n",
    "    \n",
    "    # backquery the neural network\n",
    "    # we'll use the same termnimology to each item, \n",
    "    # eg target are the values at the right of the network, albeit used as input\n",
    "    # eg hidden_output is the signal to the right of the middle nodes\n",
    "    def backquery(self, targets_list):\n",
    "        # transpose the targets list to a vertical array\n",
    "        final_outputs = numpy.array(targets_list, ndmin=2).T\n",
    "        \n",
    "        # calculate the signal into the final output layer\n",
    "        final_inputs = self.inverse_activation_function(final_outputs)\n",
    "\n",
    "        # calculate the signal out of the hidden layer\n",
    "        hidden_outputs = numpy.dot(self.who.T, final_inputs)\n",
    "        # scale them back to 0.01 to .99\n",
    "        hidden_outputs -= numpy.min(hidden_outputs)\n",
    "        hidden_outputs /= numpy.max(hidden_outputs)\n",
    "        hidden_outputs *= 0.98\n",
    "        hidden_outputs += 0.01\n",
    "        \n",
    "        # calculate the signal into the hideen layer\n",
    "        hidden_inputs = self.inverse_activation_function(hidden_outputs)\n",
    "        \n",
    "        # calculate the signal out of the input layer\n",
    "        inputs = numpy.dot(self.wih.T, hidden_inputs)\n",
    "        # scale them back to 0.01 to .99\n",
    "        inputs -= numpy.min(inputs)\n",
    "        inputs /= numpy.max(inputs)\n",
    "        inputs *= 0.98\n",
    "        inputs += 0.01\n",
    "        \n",
    "        return inputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# number of input, hidden and output nodes\n",
    "input_nodes = 784\n",
    "hidden_nodes = 200\n",
    "output_nodes = 10\n",
    "\n",
    "# learning rate\n",
    "learning_rate = 0.1\n",
    "\n",
    "# create instance of neural network\n",
    "n = neuralNetwork(input_nodes,hidden_nodes,output_nodes, learning_rate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# load the mnist training data CSV file into a list\n",
    "training_data_file = open(\"mnist_dataset/mnist_train.csv\", 'r')\n",
    "training_data_list = training_data_file.readlines()\n",
    "training_data_file.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# train the neural network\n",
    "\n",
    "# epochs is the number of times the training data set is used for training\n",
    "epochs = 5\n",
    "\n",
    "for e in range(epochs):\n",
    "    # go through all records in the training data set\n",
    "    for record in training_data_list:\n",
    "        # split the record by the ',' commas\n",
    "        all_values = record.split(',')\n",
    "        # scale and shift the inputs\n",
    "        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01\n",
    "        # create the target output values (all 0.01, except the desired label which is 0.99)\n",
    "        targets = numpy.zeros(output_nodes) + 0.01\n",
    "        # all_values[0] is the target label for this record\n",
    "        targets[int(all_values[0])] = 0.99\n",
    "        n.train(inputs, targets)\n",
    "        pass\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# load the mnist test data CSV file into a list\n",
    "test_data_file = open(\"mnist_dataset/mnist_test.csv\", 'r')\n",
    "test_data_list = test_data_file.readlines()\n",
    "test_data_file.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# test the neural network\n",
    "\n",
    "# scorecard for how well the network performs, initially empty\n",
    "scorecard = []\n",
    "\n",
    "# go through all the records in the test data set\n",
    "for record in test_data_list:\n",
    "    # split the record by the ',' commas\n",
    "    all_values = record.split(',')\n",
    "    # correct answer is first value\n",
    "    correct_label = int(all_values[0])\n",
    "    # scale and shift the inputs\n",
    "    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01\n",
    "    # query the network\n",
    "    outputs = n.query(inputs)\n",
    "    # the index of the highest value corresponds to the label\n",
    "    label = numpy.argmax(outputs)\n",
    "    # append correct or incorrect to list\n",
    "    if (label == correct_label):\n",
    "        # network's answer matches correct answer, add 1 to scorecard\n",
    "        scorecard.append(1)\n",
    "    else:\n",
    "        # network's answer doesn't match correct answer, add 0 to scorecard\n",
    "        scorecard.append(0)\n",
    "        pass\n",
    "    \n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "performance =  0.9734\n"
     ]
    }
   ],
   "source": [
    "# calculate the performance score, the fraction of correct answers\n",
    "scorecard_array = numpy.asarray(scorecard)\n",
    "print (\"performance = \", scorecard_array.sum() / scorecard_array.size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 149,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0.99  0.01  0.01  0.01  0.01  0.01  0.01  0.01  0.01  0.01]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x11c49da90>"
      ]
     },
     "execution_count": 149,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x11c033b70>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# run the network backwards, given a label, see what image it produces\n",
    "\n",
    "# label to test\n",
    "label = 0\n",
    "# create the output signals for this label\n",
    "targets = numpy.zeros(output_nodes) + 0.01\n",
    "# all_values[0] is the target label for this record\n",
    "targets[label] = 0.99\n",
    "print(targets)\n",
    "\n",
    "# get image data\n",
    "image_data = n.backquery(targets)\n",
    "\n",
    "# plot image data\n",
    "matplotlib.pyplot.imshow(image_data.reshape(28,28), cmap='Greys', interpolation='None')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
